package com.testing.sunnycommon.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.testing.sunnycommon.annotations.SunnyAdvice;
import com.testing.sunnycommon.model.Result;
import com.testing.sunnycommon.model.SunnyProject;
import com.testing.sunnycommon.model.SunnyResult;
import com.testing.sunnycommon.model.SunnyResultDetail;
import com.testing.sunnycommon.service.SunnyProjectService;
import com.testing.sunnycommon.service.SunnyResultDetailService;
import com.testing.sunnycommon.service.SunnyResultService;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.util.List;

/**
 * @Classname SunnyResultController
 * @Description 类型说明
 * @Date 2023/5/31 21:53
 * @Created by 特斯汀Roy
 */
@RestController
@RequestMapping("/sunnyResult")
@Slf4j
public class SunnyResultController {

    @Autowired
    SunnyResultService sunnyResultService;

    @Autowired
    SunnyResultDetailService sunnyResultDetailService;

    @Autowired
    SunnyProjectService sunnyProjectService;

    @ApiOperation("查询所有的测试结果")
    @GetMapping
    public Result<List<SunnyResult>> listAllResults() {
        List<SunnyResult> list = sunnyResultService.list();
        return Result.success(list);
    }

    @ApiOperation("查询项目下的所有执行结果")
    @GetMapping("/InProject/{projectId}")
    public Result<List<SunnyResult>> listResultInProject(@PathVariable Long projectId) {
        List<SunnyResult> list = sunnyResultService.list(new LambdaQueryWrapper<SunnyResult>()
                .eq(SunnyResult::getProjectId, projectId));
        return Result.success(list);
    }

    @ApiOperation("根据id查询一条执行结果")
    @GetMapping("/{id}")
    public Result<SunnyResult> getResult(@PathVariable Long id) {
        SunnyResult sunnyResult = sunnyResultService.getOne(new LambdaQueryWrapper<SunnyResult>()
                .eq(SunnyResult::getId, id));
        return Result.success(sunnyResult);
    }


    @ApiOperation("查询执行结果下的详情信息")
    @GetMapping("/{resultId}/detail")
    public Result<List<SunnyResultDetail>> listResultDetailsInResult(@PathVariable Long resultId) {
        List<SunnyResultDetail> sunnyResultDetailListInResult = sunnyResultDetailService.list(new LambdaQueryWrapper<SunnyResultDetail>()
                .eq(SunnyResultDetail::getResultId, resultId));
        return Result.success(sunnyResultDetailListInResult);
    }

    @SunnyAdvice("删除执行结果")
    @ApiOperation("删除一条执行结果")
    @DeleteMapping("/{id}")
    public Result deleteResult(@PathVariable Long id) {
        SunnyResult sunnyResult = sunnyResultService.getById(id);
        SunnyProject project = sunnyProjectService.getById(sunnyResult.getProjectId());
        boolean result = sunnyResultService.removeById(id);
        if (result) {
            return Result.success("删除项目【" + project.getName() + "】的第#" + sunnyResult.getBuildOrder() + "次执行结果成功", sunnyResult);
        } else {
            return Result.fail(1030, "删除结果失败", "请检查日志信息");
        }
    }

    /***
     * 第一种下载写法，通过httpServletResponse直接将workbook写入输出流
     * @param response 原生httpServlet返回对象，通过调用它的输出流完成文件返回
     * @param resultId 需要下载的结果id
     */
    @ApiOperation("下载执行结果的详情信息excel")
    @GetMapping("/{resultId}/download")
    public void downloadResult(HttpServletResponse response, @ApiParam("需要下载的结果id") @PathVariable Long resultId) {
        //下载的文件的名字拼接，项目名#次数作为文件名
        SunnyResult sunnyResult = sunnyResultService.getById(resultId);
        String projectName = sunnyProjectService.getById(sunnyResult.getProjectId()).getName();
        Long buildOrder = sunnyResult.getBuildOrder();
        String fileName = projectName + "#" + buildOrder + ".xlsx";
        XSSFWorkbook workbook = sunnyResultService.exportResult(resultId);
        //完成文件流格式的返回
        //需要将文件名做一下url编码转化，转成utf8格式。
        try {
            //设置返回头，让返回内容能够正常被客户端接收。
            response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf-8"));
            response.setContentType("application/vnd.ms-excel;charset=UTF-8");
            //将workbook内容，通过文件输出流，写到返回中，最后通过接口返回
            workbook.write(response.getOutputStream());
        } catch (Exception e) {
            log.error("生成excel文件失败", e.fillInStackTrace());
        } finally {
            try {
                workbook.close();
            } catch (IOException e) {
                log.error("关闭workbook失败", e.fillInStackTrace());
            }
        }
    }


    /**
     * 第二种下载写法，保存文件到服务器，通过ResponseEntity返回url资源进行下载。
     *
     * @param resultId 需要下载的结果id
     * @return 返回格式为ResponseEntity返回实体，自行设置返回
     */
    @ApiOperation("保存文件并以url资源形式下载执行结果的详情信息excel")
    @GetMapping("/{resultId}/downloadResFile")
    public ResponseEntity downloadResultFile(@ApiParam("需要下载的结果id") @PathVariable Long resultId) {
        //下载的文件的名字拼接，项目名#次数作为文件名
        SunnyResult sunnyResult = sunnyResultService.getById(resultId);
        String projectName = sunnyProjectService.getById(sunnyResult.getProjectId()).getName();
        Long buildOrder = sunnyResult.getBuildOrder();
        String fileName = projectName + "#" + buildOrder + ".xlsx";
        XSSFWorkbook workbook = sunnyResultService.exportResult(resultId);
        //将workbook保存为服务器上的文件
        File resultFile = new File("auto-logs/results/" + fileName);
        try {
            //将workbook中的内容通过输出流写到文件中，也就是先在服务器生成一个excel文件
            FileOutputStream outputStream = new FileOutputStream(resultFile);
            workbook.write(outputStream);
            outputStream.flush();
            outputStream.close();
            workbook.close();
            //基于文件创建URL资源进行拉取
            Resource resource = new UrlResource("file:" + URLEncoder.encode(resultFile.getPath(), "utf-8"));

            HttpHeaders headers = new HttpHeaders();
            //设置content-disposition 中的文件名，等价于 attachment;filename=文件名 的头设置
            headers.setContentDispositionFormData("attachment", URLEncoder.encode(fileName, "utf-8"));
            return ResponseEntity.ok()
                    .headers(headers)
                    //设置contentType为excel格式并返回资源
                    .contentType(MediaType.parseMediaType("application/vnd.ms-excel"))
                    .body(resource);
        } catch (Exception e) {
            log.error("excel文件格式返回出错", e.fillInStackTrace());
            return ResponseEntity.badRequest().body("excel文件格式返回失败");
        }
    }

    /**
     * 第三种写法，不保存文件到服务器，而是将返回结果生成字节数组资源返回
     *
     * @param resultId 需要下载的结果id
     * @return 返回格式为ResponseEntity返回实体，自行设置返回
     */
    @ApiOperation("以字节数组形式下载执行结果的详情信息excel")
    @GetMapping("/{resultId}/downloadResByte")
    public ResponseEntity downloadResultByte(@ApiParam("需要下载的结果id") @PathVariable Long resultId) {
        //下载的文件的名字拼接，项目名#次数作为文件名
        SunnyResult sunnyResult = sunnyResultService.getById(resultId);
        String projectName = sunnyProjectService.getById(sunnyResult.getProjectId()).getName();
        Long buildOrder = sunnyResult.getBuildOrder();
        String fileName = projectName + "#" + buildOrder + ".xlsx";
        XSSFWorkbook workbook = sunnyResultService.exportResult(resultId);
        try {
            //将excel内容写入到字节输出流
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            workbook.write(outputStream);
            //将输出流转为字节数组
            byte[] excelBytes = outputStream.toByteArray();
            //创建字节数组资源
            ByteArrayResource byteArrayResource = new ByteArrayResource(excelBytes);
            //设置请求头，并返回资源
            HttpHeaders headers = new HttpHeaders();
            headers.setContentDispositionFormData("attachment", URLEncoder.encode(fileName, "utf-8"));
            return ResponseEntity.ok()
                    .headers(headers)
                    .contentType(MediaType.parseMediaType("application/vnd.ms-excel"))
                    .body(byteArrayResource);
        } catch (IOException e) {
            log.error("excel文件流写入错误", e.fillInStackTrace());
            return ResponseEntity.badRequest().body("excel文件字节流转换失败");
        }
    }

    @ApiOperation("获取图片")
    @GetMapping("/errorShot/{resultDetailId}")
    public ResponseEntity getErrorShotPicture(@PathVariable Long resultDetailId) {
        //基于请求Id查询shotPath
        String shotPath = sunnyResultDetailService.getById(resultDetailId).getShotPath();
        File imgFile = new File(shotPath);
        //如果文件不存在则返回notFound
        if (!imgFile.exists()) {
            return ResponseEntity.notFound().build();
        }
        try {
            byte[] imageBytes = Files.readAllBytes(imgFile.toPath());
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.IMAGE_PNG);
            return ResponseEntity.ok()
                    .headers(headers)
                    .body(imageBytes);
        } catch (IOException e) {
            log.error("获取文件图片失败", e.fillInStackTrace());
            return ResponseEntity.badRequest().body("获取文件图片失败");
        }

    }


}
